package meta.api.web.account.presentation;

import java.util.Date;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.google.code.kaptcha.Constants;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import meta.api.web.account.businesscontrol.UserMngBusiCtrl;
import meta.api.web.account.businessinfo.UserInfo;
import meta.api.web.account.conf.AccountConfParser;
import meta.api.web.common.util.ApiConst;
import meta.api.web.common.util.ApiUtil;
import meta.common.util.JsonUtil;
import meta.common.util.JwtUtil;
import meta.common.util.StrUtil;
import meta.common.util.WebUtil;

@Controller
@RequestMapping(value="api/account")
@Tag(name = "用户管理", description = "用户管理")
public class UserMngController {

    private static final String FUNC_NM = "用户管理机能";

    private static final String ERROR_MSG_DATA_ERROR= "请求数据错误";
    private static final String ERROR_MSG_CODE_ERROR= "验证码错误";
    private static final String ERROR_MSG_CODE_EXPIRED = "验证码已过期";
    private static final String ERROR_MSG_ACCOUNT_EXIST = "账号已存在";
    private static final String ERROR_MSG_ACCOUNT_ERROR = "用户名或者密码错误";
    private static final String ERROR_MSG_CODE_OLD_PSWD_ERROR= "验证码或者旧密码错误";
    private static final String ERROR_MSG_OLD_PSWD_ERROR= "旧密码错误";

    @Autowired
    private UserMngBusiCtrl userMngBusiCtrl;

    /**
     * 用户注册
     * 
     * @param req 请求
     * @param res 响应
     * @return
     * @throws Exception 异常
     */
    @PostMapping(value="/signup")
    @Operation(tags = "用户注册", description = "用户注册")
    public String signup(HttpServletRequest req, HttpServletResponse res) throws Exception {
        ApiUtil.callApiLog(req, FUNC_NM, "用户注册", null);

        UserInfo inputUser = JsonUtil.toObj(ApiUtil.readTxtBody(req), UserInfo.class);

        if (inputUser == null) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_DATA_ERROR);
            return null;
        }

        String reqCode = inputUser.getCode();
        if (StrUtil.isEmpty(reqCode)) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_CODE_ERROR);
            return null;
        }

        // 取得注册选项设定值
        // 设定值=true 的场合，验证码检证区分=邮件验证码
        // 设定值=false的场合，验证码检证区分=图片验证码
        boolean signupOptions = AccountConfParser.getInstance().getSignupOptions();

        // get session
        HttpSession session = req.getSession();

        String sesCode = null;
        Long sesTime = null;
        if (signupOptions) {
            sesCode = (String) session.getAttribute(ApiConst.SESSION_DYNAMIC_CODE_VALUE_SIGNUP);
            sesTime = (Long) session.getAttribute(ApiConst.SESSION_DYNAMIC_CODE_DATE_SIGNUP);
        } else {
            sesCode = (String) session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
            sesTime = (Long) session.getAttribute(Constants.KAPTCHA_SESSION_DATE);
        }

        if (StrUtil.isEmpty(sesCode) || sesTime == null) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_CODE_EXPIRED);
            return null;
        }

        long intervalSeconds = (System.currentTimeMillis() - sesTime) / 1000;
        if (intervalSeconds > ApiConst.CAPTCHA_EXPIRY_SECONDS) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_CODE_EXPIRED);
            return null;
        }

        if (!reqCode.equalsIgnoreCase(sesCode)) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_CODE_ERROR);
            return null;
        }

        if (userMngBusiCtrl.checkExistAccount(inputUser.getAccount())) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_ACCOUNT_EXIST);
            return null;
        }

        // rebuild
        inputUser.rebuildByAccount();

        // 注册新用户
        userMngBusiCtrl.registerUser(inputUser);

        // 取得新用户详细情报
        UserInfo outputUser = userMngBusiCtrl.getUser(inputUser.getAccount(), false);
        // 设置权限令牌
        outputUser.setToken(JwtUtil.buildToken(inputUser.getAccount(), inputUser.getPassword(), 24));

        // clear session
        if (signupOptions) {
            session.removeAttribute(ApiConst.SESSION_DYNAMIC_CODE_VALUE_SIGNUP);
            session.removeAttribute(ApiConst.SESSION_DYNAMIC_CODE_DATE_SIGNUP);
        } else {
            session.removeAttribute(Constants.KAPTCHA_SESSION_KEY);
            session.removeAttribute(Constants.KAPTCHA_SESSION_DATE);
        }

        ApiUtil.setJsonResponse(res, JsonUtil.toJsonStr(outputUser));
        return null;
    }

    /**
     * 用户登录
     * 
     * @param req 请求
     * @param res 响应
     * @return
     * @throws Exception 异常
     */
    @PostMapping(value="/login")
    @Operation(tags = "用户登录", description = "用户登录")
    public String login(HttpServletRequest req, HttpServletResponse res) throws Exception {
        ApiUtil.callApiLog(req, FUNC_NM, "用户登录", null);

        UserInfo inputUser = JsonUtil.toObj(ApiUtil.readTxtBody(req), UserInfo.class);

        if (inputUser == null) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_DATA_ERROR);
            return null;
        }

        // 检证登录用户
        boolean valid = userMngBusiCtrl.checkLogin(inputUser.getAccount(), inputUser.getPassword());
        if (!valid) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_ACCOUNT_ERROR);
            return null;
        }

        // 取得登录用户详细情报
        UserInfo outputUser = userMngBusiCtrl.getUser(inputUser.getAccount(), false);
        int expiresHours = 24;
        if (Boolean.TRUE.equals(inputUser.getRemember())) {
            expiresHours = expiresHours * 365;
        }
        // 设置权限令牌
        outputUser.setToken(JwtUtil.buildToken(inputUser.getAccount(), inputUser.getPassword(), expiresHours));

        ApiUtil.setJsonResponse(res, JsonUtil.toJsonStr(outputUser));
        return null;
    }

    /**
     * 获取登录信息
     * 
     * @param req 请求
     * @param res 响应
     * @return
     * @throws Exception 异常
     */
    @GetMapping(value="/profile")
    @Operation(tags = "获取登录信息", description = "获取登录信息")
    public String profile(HttpServletRequest req, HttpServletResponse res) throws Exception {
        ApiUtil.callApiLog(req, FUNC_NM, "获取登录信息", null);

        String account = WebUtil.getUserAccount(req);
        if (account == null) {
            ApiUtil.setUnauthorizedResponse(req, res);
            return null;
        }

        // 取得用户详细情报
        UserInfo outputUser = userMngBusiCtrl.getUser(account, false);

        ApiUtil.setJsonResponse(res, JsonUtil.toJsonStr(outputUser));
        return null;
    }

    /**
     * 找回密码/修改密码
     * 
     * @param req 请求
     * @param res 响应
     * @return
     * @throws Exception 异常
     */
    @PostMapping(value="/password/update")
    @Operation(tags = "找回密码/修改密码", description = "找回密码/修改密码")
    public String updatePassword(HttpServletRequest req, HttpServletResponse res) throws Exception {
        ApiUtil.callApiLog(req, FUNC_NM, "找回密码/修改密码", null);

        UserInfo inputUser = JsonUtil.toObj(ApiUtil.readTxtBody(req), UserInfo.class);

        if (inputUser == null) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_DATA_ERROR);
            return null;
        }

        // 验证码/旧密码
        String reqCode = inputUser.getCode();
        if (StrUtil.isEmpty(reqCode)) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_CODE_OLD_PSWD_ERROR);
            return null;
        }

        // get session
        HttpSession session = req.getSession();

        String sesCode = (String) session.getAttribute(ApiConst.SESSION_DYNAMIC_CODE_VALUE_FORGET);
        Long sesTime = (Long) session.getAttribute(ApiConst.SESSION_DYNAMIC_CODE_DATE_FORGET);

        if (StrUtil.isNotEmpty(sesCode) && sesTime != null) {
            //----------
            // 找回密码处理
            //----------

            long intervalSeconds = (System.currentTimeMillis() - sesTime) / 1000;
            if (intervalSeconds > ApiConst.CAPTCHA_EXPIRY_SECONDS) {
                ApiUtil.setErrorJsonResponse(res, ERROR_MSG_CODE_EXPIRED);
                return null;
            }

            if (!reqCode.equalsIgnoreCase(sesCode)) {
                ApiUtil.setErrorJsonResponse(res, ERROR_MSG_CODE_ERROR);
                return null;
            }
        } else {
            //----------
            // 修改密码处理
            //----------

            // 取得用户账号
            String account = WebUtil.getUserAccount(req);
            if (account == null) {
                ApiUtil.setErrorJsonResponse(res, ERROR_MSG_ACCOUNT_ERROR);
                return null;
            }

            inputUser.setAccount(account);

            boolean valid = userMngBusiCtrl.checkLogin(inputUser.getAccount(), inputUser.getCode());
            if (!valid) {
                ApiUtil.setErrorJsonResponse(res, ERROR_MSG_OLD_PSWD_ERROR);
                return null;
            }
        }

        // 更新密码
        userMngBusiCtrl.updatePassword(inputUser.getAccount(), inputUser.getPassword());

        // 取得用户详细情报
        UserInfo outputUser = userMngBusiCtrl.getUser(inputUser.getAccount(), false);
        // 设置权限令牌
        outputUser.setToken(JwtUtil.buildToken(inputUser.getAccount(), inputUser.getPassword(), 24));

        // clear session
        session.removeAttribute(ApiConst.SESSION_DYNAMIC_CODE_VALUE_FORGET);
        session.removeAttribute(ApiConst.SESSION_DYNAMIC_CODE_DATE_FORGET);

        ApiUtil.setJsonResponse(res, JsonUtil.toJsonStr(outputUser));

        return null;
    }

    /**
     * 更新邮箱
     * 
     * @param req 请求
     * @param res 响应
     * @return
     * @throws Exception 异常
     */
    @PostMapping(value="/email/update")
    @Operation(tags = "更新邮箱", description = "更新邮箱")
    public String updateEmail(HttpServletRequest req, HttpServletResponse res) throws Exception {
        ApiUtil.callApiLog(req, FUNC_NM, "更新邮箱", null);

        UserInfo inputUser = JsonUtil.toObj(ApiUtil.readTxtBody(req), UserInfo.class);

        if (inputUser == null) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_DATA_ERROR);
            return null;
        }

        // 验证码
        String reqCode = inputUser.getCode();
        if (StrUtil.isEmpty(reqCode)) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_CODE_ERROR);
            return null;
        }

        // get session
        HttpSession session = req.getSession();

        String sesCode = (String) session.getAttribute(ApiConst.SESSION_DYNAMIC_CODE_VALUE_EMAIL);
        Long sesTime = (Long) session.getAttribute(ApiConst.SESSION_DYNAMIC_CODE_DATE_EMAIL);

        if (StrUtil.isEmpty(sesCode) || sesTime == null) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_CODE_EXPIRED);
            return null;
        }

        long intervalSeconds = (System.currentTimeMillis() - sesTime) / 1000;
        if (intervalSeconds > ApiConst.CAPTCHA_EXPIRY_SECONDS) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_CODE_EXPIRED);
            return null;
        }

        if (!reqCode.equalsIgnoreCase(sesCode)) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_CODE_ERROR);
            return null;
        }

        // 取得登录用户详细情报
        UserInfo loginUser = WebUtil.getLoginUser(req);

        inputUser.setId(loginUser.getId());
        inputUser.setAccount(loginUser.getAccount());

        // 更新邮箱
        userMngBusiCtrl.updateEmail(inputUser);

        // clear session
        session.removeAttribute(ApiConst.SESSION_DYNAMIC_CODE_VALUE_EMAIL);
        session.removeAttribute(ApiConst.SESSION_DYNAMIC_CODE_DATE_EMAIL);

        ApiUtil.setEmptyJsonResponse(res);

        return null;
    }

    /**
     * 获取用户注册选项信息
     * 
     * @param req 请求
     * @param res 响应
     * @return
     * @throws Exception 异常
     */
    @GetMapping(value="/signup/options")
    @Operation(tags = "获取用户注册选项信息", description = "获取用户注册选项信息")
    public String signupOptions(HttpServletRequest req, HttpServletResponse res) throws Exception {
        ApiUtil.callApiLog(req, FUNC_NM, "获取用户注册选项信息", null);
        boolean signupOptions = AccountConfParser.getInstance().getSignupOptions();
        ApiUtil.setJsonResponse(res, "{\"authCode\":" + signupOptions + "}");
        return null;
    }
}
